#include "slot_template.h"
#include "json/value.h"

#include <stdexcept>

using namespace std;

SlotTemplate::SlotTemplate( const Json::Value & _slot ) {
	dirs.left = _slot["Directions"][0u].asBool();
	dirs.middle = _slot["Directions"][1u].asBool();
	dirs.right = _slot["Directions"][2u].asBool();

	allowedCannons = _slot["AllowedCannons"].asBool();

	maxHp = _slot["MaxHp"].asInt();

	cost = SLOT_COST(SLOT_TYPE(dirs));
	cost += HP_SLOT_COST(maxHp);
	cost += LOADABLE(allowedCannons);
}

SlotTemplate::SlotTemplate( Directions _dirs, int _maxHp, bool _allowedCannons ) {
	dirs = _dirs; 
	maxHp = _maxHp;

	allowedCannons = _allowedCannons;

	cost = SLOT_COST(SLOT_TYPE(dirs));
	cost += HP_SLOT_COST(maxHp);
	cost += LOADABLE(allowedCannons);
}

SlotTemplate::SlotTemplate(int _dirs, int _maxHp, bool _allowedCannons ) {
	dirs = REV_SLOT_TYPE(_dirs); 
	maxHp = _maxHp;

	allowedCannons = _allowedCannons;

	cost = SLOT_COST(SLOT_TYPE(dirs));
	cost += HP_SLOT_COST(maxHp);
	cost += LOADABLE(allowedCannons);
}

SlotTemplate::SlotTemplate( const SlotTemplate & _other ) :
	dirs(_other.dirs),
	maxHp(_other.maxHp),
	allowedCannons(_other.allowedCannons),
	cost(_other.cost) {}

bool SlotTemplate::operator==(const SlotTemplate& other ) const {
	return (
		maxHp				== other.maxHp &&
		cost 				== other.cost &&
		allowedCannons		== other.allowedCannons &&
		SLOT_TYPE(dirs)		== SLOT_TYPE(other.dirs) );
}

Json::Value SlotTemplate::convertToJson() const {
	Json::Value slot;

	slot["Type"] = "SlotTemplate";
	
	slot["Directions"][0u] = dirs.left;
	slot["Directions"][1u] = dirs.middle;
	slot["Directions"][2u] = dirs.right;

	slot["AllowedCannons"] = allowedCannons;

	slot["MaxHp"] = maxHp;
	slot["Cost"] = cost;

	return slot;
}

void SlotTemplate::setDirections ( Directions _dir ) {
	int diffSlotCost = SLOT_COST(SLOT_TYPE(_dir)) - SLOT_COST(SLOT_TYPE(dirs));
	cost += diffSlotCost;

	dirs = _dir;
}

void SlotTemplate::setDirections ( int _dir ) {
	int diffCost = SLOT_COST(_dir) - SLOT_COST(SLOT_TYPE(dirs));
	cost += diffCost;

	dirs = REV_SLOT_TYPE(_dir);
}

void SlotTemplate::invertDirections() {
	Directions _dir;
	_dir.left = dirs.right;
	_dir.middle = dirs.middle;
	_dir.right = dirs.left;

	setDirections(_dir);
}

void SlotTemplate::setMaxHp ( int _hp ) {
	if ( _hp <= 0 ) throw invalid_argument("SlotTemplate::setMaxHp(int)");
	
	int diffHpCost = HP_SLOT_COST(_hp) - HP_SLOT_COST(maxHp);
	cost += diffHpCost;

	maxHp = _hp;
}

void SlotTemplate::setAllowedCannons( bool _ac ) {
	int diffAcCost = LOADABLE(_ac) - LOADABLE(allowedCannons);
	cost += diffAcCost;

	allowedCannons = _ac;
}

void SlotTemplate::toggleAllowedCannons() {
	int diffAcCost = LOADABLE(!allowedCannons) - LOADABLE(allowedCannons);
	cost += diffAcCost;

	allowedCannons = !allowedCannons;
}

array<string, 3> SlotTemplate::getSummary() const {
	array<string, 3> summary;

	summary[0] = STRING_DIRS(dirs);
	summary[1] = STRING_AC(allowedCannons);
	summary[2] = std::to_string(cost);

	return summary;
}

Directions SlotTemplate::getDirections() const 	{return dirs;}
int SlotTemplate::getMaxHp() const 				{return maxHp;}
bool SlotTemplate::getAllowedCannons() const	{return allowedCannons;}
int SlotTemplate::getCost() const 				{return cost;}

bool SlotTemplate::compare( const SlotTemplate & a, const SlotTemplate & b ) {
	if ( a.maxHp < b.maxHp ) return true;
	if ( a.maxHp > b.maxHp ) return false;

	if ( a.cost < b.cost ) return true;
	if ( a.cost > b.cost ) return false;

	if ( a.allowedCannons < b.allowedCannons ) return true;
	if ( a.allowedCannons > b.allowedCannons ) return false;

	if ( SLOT_TYPE(a.dirs) < SLOT_TYPE(b.dirs) ) return true;
	return false;
}
